package com.foohoo.benchmark.string;

import lombok.extern.slf4j.Slf4j;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 测试不同的字符串分割方式的性能
 * Benchmark                            Mode  Cnt    Score     Error  Units
 * StringSplit.splitByIndexOfWith1Char  avgt    3  172.213 ± 363.128  ns/op
 * StringSplit.splitByIndexOfWith2Char  avgt    3   83.922 ±  22.280  ns/op
 * StringSplit.splitBySplitWith1Char    avgt    3  164.950 ±  45.064  ns/op
 * StringSplit.splitBySplitWith2Char    avgt    3  401.442 ± 381.321  ns/op
 * 一句话结论: split在单个字符的时候底层仍然采用indexOf实现，速度尚可;多字符的场景改用正则的实现，性能大幅下降
 *
 * @author mzdbxqh
 * @date 2020-10-20 13:48
 **/
@Slf4j
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Warmup(iterations = 5, time = 1)
@Measurement(iterations = 3, time = 1)
@Fork(1)
@Threads(1)
@State(Scope.Benchmark)
public class StringSplit {

	private static final String SOURCE_STRING = "hello world";

	private static final String SPLIT_STRING = "l";

	private static final String MULTI_SPLIT_STRING = "ll";

	@Benchmark
	public void splitByIndexOfWith1Char(Blackhole bh) {
		int index = SOURCE_STRING.indexOf(SPLIT_STRING);
		String right = SOURCE_STRING;
		List<String> result = new ArrayList<>();
		while (index >= 0) {
			if (index > 0) {
				result.add(right.substring(0, index));
			}
			right = right.substring(index + SPLIT_STRING.length());
			index = right.indexOf(SPLIT_STRING);
		}
		if (right.length() != 0) {
			result.add(right);
		}
		bh.consume(result);
	}

	@Benchmark
	public void splitBySplitWith1Char(Blackhole bh) {
		String[] arr = SOURCE_STRING.split(SPLIT_STRING);
		bh.consume(arr);
	}

	@Benchmark
	public void splitByIndexOfWith2Char(Blackhole bh) {
		int index = SOURCE_STRING.indexOf(MULTI_SPLIT_STRING);
		String right = SOURCE_STRING;
		List<String> result = new ArrayList<>();
		while (index >= 0) {
			if (index > 0) {
				result.add(right.substring(0, index));
			}
			right = right.substring(index + MULTI_SPLIT_STRING.length());
			index = right.indexOf(MULTI_SPLIT_STRING);
		}
		if (right.length() != 0) {
			result.add(right);
		}
		bh.consume(result);
	}

	@Benchmark
	public void splitBySplitWith2Char(Blackhole bh) {
		String[] arr = SOURCE_STRING.split(MULTI_SPLIT_STRING);
		bh.consume(arr);
	}
}
